#pragma once

#include <vector>
#include <algorithm>
#include <Windows.h>
#include <gdiplus.h>
#include "T_Ref.h"
#include "T_Action.h"


enum MouseEvent{
	MouseIn,
	MouseOut
};

enum TouchEvent{
	TouchBegin,
	TouchMove,
	TouchEnd,
	TouchCanceled
};

class T_Node;
class T_Scene;

typedef void (T_Ref::*MouseEventCallee)(T_Node *,int,int,MouseEvent);
typedef void (T_Ref::*TouchEventCallee)(T_Node *,int,int,TouchEvent);


class T_Node:public T_Ref{
protected:
	Gdiplus::PointF m_Position;
	Gdiplus::SizeF m_Size;
	float m_RealScaleX;
	float m_RealScaleY;
	float m_ScaleX;
	float m_ScaleY;
	bool m_CascadeScaleEnabled;
	int m_LocalZOrder;
	int m_ZOrder;
	bool m_MyVisible;
	bool m_Visible;
	short m_Alpha;

	bool m_Touchable;
	T_Ref *m_MouseEventCaller;
	MouseEventCallee m_MouseEventCallee;
	T_Ref *m_TouchEventCaller;
	TouchEventCallee m_TouchEventCallee;

	Gdiplus::RectF m_WorldBounds;
	std::vector<T_Node *>m_Children;
	T_Node *m_Parent;
	int m_Tag;
	int m_Ref;
	bool m_Sorted;
public:
	T_Node();
	virtual ~T_Node();

	void setPosition(const Gdiplus::PointF &p);
	Gdiplus::PointF getPosition(){return m_Position;}
	Gdiplus::RectF getWorldBounds(){return m_WorldBounds;}
	Gdiplus::PointF getWorldPosition(){return Gdiplus::PointF(m_WorldBounds.X,m_WorldBounds.Y);}
	Gdiplus::PointF getBaseZero();
	void updatePosition();

	void setVisible(bool v){m_MyVisible=v;updateVisible();}
	bool isVisible(){return m_Visible;}
	void updateVisible();

	void setSize(const Gdiplus::SizeF &s);
	Gdiplus::SizeF getSize(){return m_Size;}
	void updateSize();

	int getZOrder(){return m_ZOrder;}
	void setLocalZOrder(int z);
	void updateZOrder();
	int getLocalZOrder(){return m_LocalZOrder;}

	void setCascadeScaleEnabled(bool b){m_CascadeScaleEnabled=b;}
	void setScaleX(float scale);
	void setScaleY(float scale);
	float getScaleX(){return m_ScaleX;}
	float getScaleY(){return m_ScaleY;}
	void setScale(float scale);
	void updateScale();

	void setTag(int tag){m_Tag=tag;}
	int getTag(){return m_Tag;}
	T_Node *getChildByTag(int tag);

	void setAlpha(short alpha){m_Alpha=alpha>255?255:alpha<0?0:alpha;}
	short getAlpha(){return m_Alpha;}

	void setTouchEnabled(bool b);
	bool isTouchEnabled(){return m_Touchable;}
	void addMouseEventListener(T_Ref *r,MouseEventCallee e);
	void addTouchEventListener(T_Ref *r,TouchEventCallee e);
	void onMouseEvent(int x,int y,MouseEvent e);
	void onTouch(int x,int y,TouchEvent e);

	void runAction(T_Action *action);
	virtual bool addChild(T_Node *n);
	virtual void onRemove();
	T_Node *getParent(){return m_Parent;}
	std::vector<T_Node *>&getChildren(){return m_Children;}
	void removeChild(T_Node *n);
	void removeAllChildren();
	T_Scene *getScene();

	void paint(HDC hdc);
	virtual void onPaint(HDC hdc)=0;
	virtual void onSizeChanged(const Gdiplus::SizeF &prev){}
	virtual void onPositionChanged(const Gdiplus::PointF &prev){}
};